/*
 * To change this license header, choose License Headers in Project Properties.
 * To change this template file, choose Tools | Templates
 * and open the template in the editor.
 */
package com.jili.ubert;

import static com.jili.ubert.ResourceManager.OrderQuenes;
import static com.jili.ubert.ResourceManager.Orderlist;
import com.jili.ubert.code.client2server.AlterOrder;
import com.jili.ubert.code.client2server.BasketCancelOrders;
import com.jili.ubert.code.client2server.BasketOrders;
import com.jili.ubert.code.client2server.CancelOrder;
import com.jili.ubert.code.client2server.NewOrder;
import com.jili.ubert.code.server2client.Price;
import com.jili.ubert.dao.NewHibernateUtil;
import com.jili.ubert.dao.sim.TradeSimOrderquene;
import java.io.IOException;
import java.sql.Date;
import java.sql.Time;
import java.time.LocalDate;
import java.time.LocalTime;
import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.avis.client.NotificationEvent;
import org.avis.client.NotificationListener;

/**
 *
 * @author ChengJiLi
 */
class AcceptOrder implements NotificationListener {

    private static int runType = 1;//运行模式，1：撮合成交，2.全部成交，3.挂单，只在type为1模拟成交中有效
    private static final Log log = LogFactory.getLog(AcceptOrder.class);

    public AcceptOrder(int runType) {
        this.runType = runType;
    }

    public AcceptOrder() {
    }

    @Override
    public void notificationReceived(NotificationEvent ne) {
        log.info("Title:" + ne.notification.getString("Title")
                + "  PipID:" + ne.notification.getInt("PipID")
                + "  OrderType:" + ne.notification.getInt("OrderType")
                + "  Data:" + ne.notification.get("Data"));
        int orderType = ne.notification.getInt("OrderType");
        byte[] dd = ne.notification.getOpaque("Data");
        /*
         1.回送回报：收到委托回报
         2.执行逻辑检查匹配
         3.推送成交回报
         4.注意：3，4，5只涉及直接修改订单队列不用撮合成交，1）会委托回报，2）回完成状态回报
         1,2如果不能立即成交，加入到订单队列，队列缓存到数据库，宕机后还能正常恢复；
         2.要分别拆成1执行
         5.需要一个回报构建类
         */
        /*
         1.解码，调用deal
         OrderType:1,2,3,4,5-模拟交易1，6,7,8-内部成交2，单笔，撤单，改价，9-内部移仓3，10，内部修正订单状态4；
        
         */
        switch (orderType) {
            case 1: {//模拟成交单笔委托
                NewOrder order = new NewOrder();
                try {
                    order = order.DeCode(dd);
                    deal(order, 1);
                } catch (IOException ex) {
                    log.error(ex);
                }
                break;
            }
            case 2: {//模拟成交篮子委托
                BasketOrders basketorders = new BasketOrders();
                try {
                    basketorders = basketorders.DeCode(dd);
                    deal(basketorders);
                } catch (IOException ex) {
                    log.error(ex);
                }
                break;
            }
            case 3: {//模拟成交改单
                AlterOrder alterOrder = new AlterOrder();
                try {
                    alterOrder = alterOrder.DeCode(dd);
                    deal(alterOrder, 1);
                } catch (IOException ex) {
                    log.error(ex);
                }
                break;
            }
            case 4: {//模拟成交撤单
                CancelOrder cancelOrder = new CancelOrder();
                try {
                    cancelOrder = cancelOrder.DeCode(dd);
                    deal(cancelOrder, 1);
                } catch (IOException ex) {
                    log.error(ex);
                }
                break;
            }
            case 5: {//模拟成交篮子撤单
                BasketCancelOrders bCancelOrders = new BasketCancelOrders();
                try {
                    bCancelOrders = bCancelOrders.DeCode(dd);
                    deal(bCancelOrders);
                } catch (IOException ex) {
                    log.error(ex);
                }
                break;
            }
            case 6: {//内部成交单笔
                NewOrder order = new NewOrder();
                try {
                    order = order.DeCode(dd);
                    deal(order, 2);
                } catch (IOException ex) {
                    log.error(ex);
                }
                break;
            }
            case 7: {//内部成交改单
                AlterOrder alterOrder = new AlterOrder();
                try {
                    alterOrder = alterOrder.DeCode(dd);
                    deal(alterOrder, 2);
                } catch (IOException ex) {
                    log.error(ex);
                }
                break;
            }
            case 8: {//内部成交撤单
                CancelOrder cancelOrder = new CancelOrder();
                try {
                    cancelOrder = cancelOrder.DeCode(dd);
                    deal(cancelOrder, 2);
                } catch (IOException ex) {
                    log.error(ex);
                }
                break;
            }
            case 9: {//内部移仓
                NewOrder order = new NewOrder();
                try {
                    order = order.DeCode(dd);
                    //    deal(order, 3);
                } catch (IOException ex) {
                    log.error(ex);
                }
                break;
            }
            case 10: {//内部修正订单状态
                NewOrder order = new NewOrder();
                try {
                    order = order.DeCode(dd);
                    //    deal(order, 4);
                } catch (IOException ex) {
                    log.error(ex);
                }
                break;
            }
            default: {
                log.error("错误的数据类型：" + dd);
                break;
            }
        }
    }
    /*
     deal处理流程
     1.发送委托回报
     2.判断订单价格类型，市价直接成交，发送成交回报
     2.判断限价单价格与最新价，最新价优先，按买手最低价，卖手高价成交；直接成交发送成交回报
     3.待成交的，放入订单表中
     */

    private TradeSimOrderquene getSimOrderquene(NewOrder order) {
        TradeSimOrderquene orderq = new TradeSimOrderquene();
        orderq.setAccountCode(order.getAccountCode());
        orderq.setBs(order.getBs());
        orderq.setCancelQty(0);
        orderq.setClassCode(order.getClassCode());
        orderq.setDealerUserId(order.getDealerUserId());
        //   if (!order.getDateTimeStr().equals("") || order.getDateTimeStr() != null) {
        orderq.setDateTime(Date.valueOf(LocalDate.now()));
        //   }
        orderq.setTime(Time.valueOf(LocalTime.now()));
        orderq.setExeQty(0);
        orderq.setHedgeFlag(order.getHedgeFlag());
        orderq.setIp4(order.getIp4());
        orderq.setMac(order.getMac());
        orderq.setMarketCode(order.getMarketCode());
        orderq.setObj(order.getObj());
        orderq.setOpenClose(order.getOpenClose());
        orderq.setOrderId(order.getOrderId());
        orderq.setOrderPrice(order.getOrderPrice());
        orderq.setOrderQty(order.getOrderQty());
        orderq.setPosId(order.getPosId());
        orderq.setPriceType(order.getPriceType());
        orderq.setTradeDate(Date.valueOf(LocalDate.now()));
        orderq.setWorkingQty(order.getOrderQty());
        return orderq;
    }

    private void putinSimOrderquene(NewOrder order) {
        TradeSimOrderquene data = this.getSimOrderquene(order);
        Orderlist.put(data.getOrderId(), data);
        if (!OrderQuenes.containsKey(data.getObj() + "_" + data.getMarketCode())) {
            OrderQuene oq = new OrderQuene();
            OrderQuenes.put(data.getObj() + "_" + data.getMarketCode(), oq);
        }
        OrderQuenes.get(data.getObj() + "_" + data.getMarketCode()).put(data.getOrderId(), data);
        NewHibernateUtil.save(data);
    }

    private void putinSimOrderquene(TradeSimOrderquene data) {
        Orderlist.put(data.getOrderId(), data);
        if (!OrderQuenes.containsKey(data.getObj() + "_" + data.getMarketCode())) {
            OrderQuene oq = new OrderQuene();
            OrderQuenes.put(data.getObj() + "_" + data.getMarketCode(), oq);
        }
        OrderQuenes.get(data.getObj() + "_" + data.getMarketCode()).put(data.getOrderId(), data);
        NewHibernateUtil.save(data);
    }

    private int[] getBidQty(Price price) {
        int[] bidQty = new int[6];
        bidQty[0] = price.getLastQty();
        bidQty[1] = price.getBidQty1();
        bidQty[2] = price.getBidQty2();
        bidQty[3] = price.getBidQty3();
        bidQty[4] = price.getBidQty4();
        bidQty[5] = price.getBidQty5();
        return bidQty;
    }

    private int[] getAskQty(Price price) {
        int[] AskQty = new int[6];
        AskQty[0] = price.getLastQty();
        AskQty[1] = price.getAskQty1();
        AskQty[2] = price.getAskQty2();
        AskQty[3] = price.getAskQty3();
        AskQty[4] = price.getAskQty4();
        AskQty[5] = price.getAskQty5();
        return AskQty;
    }

    private float[] getBidPrice(Price price) {
        float[] bidPrice = new float[6];
        bidPrice[0] = price.getLastPrice();
        bidPrice[1] = price.getBidPrice1();
        bidPrice[2] = price.getBidPrice2();
        bidPrice[3] = price.getBidPrice3();
        bidPrice[4] = price.getBidPrice4();
        bidPrice[5] = price.getBidPrice5();
        return bidPrice;
    }

    private float[] getAskPrice(Price price) {
        float[] askPrice = new float[6];
        askPrice[0] = price.getLastPrice();
        askPrice[1] = price.getAskPrice1();
        askPrice[2] = price.getAskPrice2();
        askPrice[3] = price.getAskPrice3();
        askPrice[4] = price.getAskPrice4();
        askPrice[5] = price.getAskPrice5();
        return askPrice;
    }

    private void MatchExeAll(NewOrder order, int type, Price price) {
        if (order.getBs().equals("B")) {
            float[] bidPrice = this.getBidPrice(price);
            int[] bidQty = this.getBidQty(price);
            int qty = order.getOrderQty();
            int i = 0;
            while (bidQty[i] != 0 && qty > 0) {
                if (qty <= bidQty[i]) {
                    ReportManager.ExecuteReport(order, qty, bidPrice[i], type);
                } else {
                    ReportManager.ExecuteReport(order, bidQty[i], bidPrice[i], type);
                    order.setOrderQty(order.getOrderQty() - bidQty[i]);
                }
                qty = qty - bidQty[i];
                i = i + 1;
                if (i > 5) {
                    break;
                }
            }
            if (qty > 0) {
                if (price.getLastPrice() != 0) {
                    ReportManager.ExecuteReport(order, qty, price.getLastPrice(), type);
                } else {
                    ReportManager.ExecuteReport(order, qty, order.getOrderPrice(), type);
                }
            }
        } else {
            float[] askPrice = this.getAskPrice(price);
            int[] askQty = this.getAskQty(price);
            int qty = order.getOrderQty();
            int i = 0;
            while (askQty[i] != 0 && qty > 0) {
                if (qty <= askQty[i]) {
                    ReportManager.ExecuteReport(order, qty, askPrice[i], type);
                } else {
                    ReportManager.ExecuteReport(order, askQty[i], askPrice[i], type);
                    order.setOrderQty(order.getOrderQty() - askQty[i]);
                }
                qty = qty - askQty[i];
                i = i + 1;
                if (i > 5) {
                    break;
                }
            }
            if (qty > 0) {
                if (price.getLastPrice() != 0) {
                    ReportManager.ExecuteReport(order, qty, price.getLastPrice(), type);
                } else {
                    ReportManager.ExecuteReport(order, qty, order.getOrderPrice(), type);
                }
            }
        }
    }

    private void MatchExe5Deal(NewOrder order, int Pricetype, Price price) {
        /*
         Pricetype:1:不成即撤单；2.不成用最新价挂单，3.不全部成交，就全部撤单
         */
        if (order.getBs().equals("B")) {
            if (price.getBidQty1() == 0) {
                ReportManager.ExeCancelReport(order, order.getOrderQty());
            } else {
                float[] bidPrice = this.getBidPrice(price);
                int[] bidQty = this.getBidQty(price);
                int qty = order.getOrderQty();
                int i = 0;
                int exeQtytotal = 0;
                if (Pricetype != 3) {
                    while (bidQty[i] != 0 && qty > 0) {
                        if (qty <= bidQty[i]) {
                            ReportManager.ExecuteReport(order, qty, bidPrice[i], 1);
                        } else {
                            ReportManager.ExecuteReport(order, bidQty[i], bidPrice[i], 1);
                            order.setOrderQty(order.getOrderQty() - bidQty[i]);
                            exeQtytotal = exeQtytotal + bidQty[i];
                        }
                        qty = qty - bidQty[i];
                        i = i + 1;
                        if (i > 5) {
                            break;
                        }
                    }
                    if (qty > 0) {
                        if (price.getLastPrice() != 0 && Pricetype == 2) {
                            TradeSimOrderquene oq = this.getSimOrderquene(order);
                            oq.setWorkingQty(qty);
                            oq.setExeQty(exeQtytotal);
                            this.putinSimOrderquene(oq);
                        } else {
                            ReportManager.ExeCancelReport(order, qty);
                        }
                    }
                } else {
                    int l5qty = 0;
                    for (int j = 0; j <= 5; j++) {
                        l5qty = l5qty + bidQty[j];
                    }
                    if (qty > l5qty) {
                        ReportManager.ExeCancelReport(order, qty);
                    } else {
                        for (int j = 0; j <= 5; j++) {
                            if (bidQty[j] != 0 && qty > bidQty[j]) {
                                ReportManager.ExecuteReport(order, bidQty[j], bidPrice[j], 1);
                                order.setOrderQty(order.getOrderQty() - bidQty[j]);
                                qty = qty - bidQty[j];
                            } else if (bidQty[j] != 0 && qty < bidQty[j]) {
                                ReportManager.ExecuteReport(order, qty, bidPrice[j], 1);

                            }
                        }
                    }
                }
            }
        } else {
            if (price.getAskQty1() == 0) {
                ReportManager.ExeCancelReport(order, order.getOrderQty());
            } else {
                float[] askPrice = this.getAskPrice(price);
                int[] askQty = this.getAskQty(price);
                int qty = order.getOrderQty();
                int i = 0;
                int exeQtytotal = 0;
                if (Pricetype != 3) {
                    while (askQty[i] != 0 && qty > 0) {
                        if (qty <= askQty[i]) {
                            ReportManager.ExecuteReport(order, qty, askPrice[i], 1);
                        } else {
                            ReportManager.ExecuteReport(order, askQty[i], askPrice[i], 1);
                            order.setOrderQty(order.getOrderQty() - askQty[i]);
                            exeQtytotal = exeQtytotal + askQty[i];
                        }
                        qty = qty - askQty[i];
                        i = i + 1;
                        if (i > 5) {
                            break;
                        }
                    }
                    if (qty > 0) {
                        if (price.getLastPrice() != 0 && Pricetype == 2) {
                            TradeSimOrderquene oq = this.getSimOrderquene(order);
                            oq.setWorkingQty(qty);
                            oq.setExeQty(exeQtytotal);
                            this.putinSimOrderquene(oq);
                        } else {
                            ReportManager.ExeCancelReport(order, qty);
                        }
                    }
                } else {
                    int l5qty = 0;
                    for (int j = 0; j <= 5; j++) {
                        l5qty = l5qty + askQty[j];
                    }
                    if (qty > l5qty) {
                        ReportManager.ExeCancelReport(order, qty);
                    } else {
                        for (int j = 0; j <= 5; j++) {
                            if (askQty[j] != 0 && qty > askQty[j]) {
                                ReportManager.ExecuteReport(order, askQty[j], askPrice[j], 1);
                                order.setOrderQty(order.getOrderQty() - askQty[j]);
                                qty = qty - askQty[j];
                            } else if (askQty[j] != 0 && qty < askQty[j]) {
                                ReportManager.ExecuteReport(order, qty, askPrice[j], 1);

                            }
                        }
                    }
                }
            }
        }
    }

    private void MatchExeOneDeal(NewOrder order, int Pricetype, Price price) {
        /*
         Pricetype:1:对手最优；2.本方最优，无对手盘撤单，1：B最新价挂,卖，最新价，，2.都是本方价挂
         */
        if (order.getBs().equals("B")) {
            if (price.getBidQty1() == 0) {
                ReportManager.ExeCancelReport(order, order.getOrderQty());
            } else {
                if (Pricetype == 1) {
                    int qty = order.getOrderQty();
                    if (qty > price.getBidQty1()) {
                        ReportManager.ExecuteReport(order, price.getBidQty1(), price.getBidPrice1(), 1);
                        TradeSimOrderquene oq = this.getSimOrderquene(order);
                        oq.setWorkingQty(qty - price.getBidQty1());
                        oq.setExeQty(price.getBidQty1());
                        oq.setOrderPrice(price.getLastPrice());
                        this.putinSimOrderquene(oq);

                    } else {
                        ReportManager.ExecuteReport(order, qty, price.getBidPrice1(), 1);
                    }
                } else {
                    TradeSimOrderquene oq = this.getSimOrderquene(order);
                    oq.setWorkingQty(order.getOrderQty());
                    oq.setExeQty(0);
                    oq.setOrderPrice(price.getAskPrice1());
                    this.putinSimOrderquene(oq);
                }
            }
        } else {
            if (price.getAskQty1() == 0) {
                ReportManager.ExeCancelReport(order, order.getOrderQty());
            } else {
                if (Pricetype == 1) {
                    int qty = order.getOrderQty();
                    if (qty > price.getAskQty1()) {
                        ReportManager.ExecuteReport(order, price.getAskQty1(), price.getAskPrice1(), 1);
                        TradeSimOrderquene oq = this.getSimOrderquene(order);
                        oq.setWorkingQty(qty - price.getAskQty1());
                        oq.setExeQty(price.getAskQty1());
                        oq.setOrderPrice(price.getLastPrice());
                        this.putinSimOrderquene(oq);

                    } else {
                        ReportManager.ExecuteReport(order, qty, price.getAskPrice1(), 1);
                    }
                } else {
                    TradeSimOrderquene oq = this.getSimOrderquene(order);
                    oq.setWorkingQty(order.getOrderQty());
                    oq.setExeQty(0);
                    oq.setOrderPrice(price.getBidPrice1());
                    this.putinSimOrderquene(oq);
                }
            }
        }
    }

    private void deal(NewOrder order, int type) {
        ReportManager.CommitReport(order, order.getOrderQty(), type);
        if (runType == 1 && type == 1) {//撮合成交    
            if (ResourceManager.PriceQuenes.containsKey(order.getObj() + "_" + order.getMarketCode())) {
                //判断订单价格类型
                Price price = ResourceManager.PriceQuenes.get(order.getObj() + "_" + order.getMarketCode());
                if (order.getPriceType().equals("0")) {//无条件市价单
                    if (order.getBs().equals("B") || order.getBs().equals("S")) {
                        this.MatchExeAll(order, type, price);
                    } else {
                        ReportManager.OtherExecuteReport(order, order.getOrderQty(), order.getOrderPrice(), type);
                    }
                } else if (order.getPriceType().equals("1")) {//限价单
                    if (order.getBs().equals("B") || order.getBs().equals("S")) {
                        this.MatchExeByPrice(order, type, price);
                    } else {
                        ReportManager.OtherExecuteReport(order, order.getOrderQty(), order.getOrderPrice(), type);
                    }
                } else {//其他单，在资源算法中处理；市价单，或是特殊限价单
                    this.dealSpecialOrder(order, price);
                }
            } else if (order.getPriceType().equals("1")) {
                this.putinSimOrderquene(order);
            } else {
                ReportManager.CommitRejectReport(order);
            }

        } else if (runType == 3 && type == 1) {//挂单，写到委托表
            //只存委托队列
            this.putinSimOrderquene(order);
        } else {//立刻成交
            ReportManager.ExecuteReport(order, order.getOrderQty(), order.getOrderPrice(), type);
        }

    }

    private void deal(BasketOrders basketorders) {
        int n = basketorders.getOrders().size();
        log.debug("篮子下单笔数：" + n);
        for (int i = 0; i < n; i++) {
            deal(basketorders.getOrders().get(i), 1);
            log.debug("执行次数：" + i);
        }
    }

    private void deal(AlterOrder alterOrder, int type) {
        ReportManager.ExecuteReport(alterOrder.getOrderId(), alterOrder.getAlterQty(), alterOrder.getAlterPrice(), type);
    }

    private void deal(CancelOrder cancelOrder, int type) {
        ReportManager.CommitReport(cancelOrder, type);
        ReportManager.ExecuteReport(cancelOrder, cancelOrder.getCancelQty(), type);
    }

    private void deal(BasketCancelOrders bCancelOrders) {
        int n = bCancelOrders.getCancelOrders().size();
        log.debug("篮子撤单笔数：" + n);
        for (int i = 0; i < n; i++) {
            log.debug("开始执行次数：" + i);
            deal(bCancelOrders.getCancelOrders().get(i), 1);
            log.debug("执行次数：" + i);
        }
    }

    private void MatchExeByPrice(NewOrder order, int type, Price price) {
        if (order.getBs().equals("B")) {
            float[] bidPrice = this.getBidPrice(price);
            int[] bidQty = this.getBidQty(price);
            int qty = order.getOrderQty();
            int i = 0;
            float price0 = order.getOrderPrice();
            int exeQtytotal = 0;
            //小于最新盘口，直接全部成交
            while (price0 >= bidPrice[i] && bidQty[i] != 0) {
                if (qty <= bidQty[i]) {
                    ReportManager.ExecuteReport(order, qty, bidPrice[i], type);
                } else {
                    ReportManager.ExecuteReport(order, bidQty[i], bidPrice[i], type);
                    exeQtytotal = exeQtytotal + bidQty[i];
                }
                qty = qty - bidQty[i];
                i = i + 1;
                if (i > 5) {
                    break;
                }
            }
            if (qty > 0) {
                TradeSimOrderquene oq = this.getSimOrderquene(order);
                oq.setWorkingQty(qty);
                oq.setExeQty(exeQtytotal);
                this.putinSimOrderquene(oq);
            }

        } else {
            float[] askPrice = this.getAskPrice(price);
            int[] askQty = this.getAskQty(price);
            int qty = order.getOrderQty();
            int i = 0;
            float price0 = order.getOrderPrice();
            int exeQtytotal = 0;
            //小于最新盘口，直接全部成交
            while (price0 <= askPrice[i] && askQty[i] != 0) {
                if (qty <= askQty[i]) {
                    ReportManager.ExecuteReport(order, qty, askPrice[i], type);
                } else {
                    ReportManager.ExecuteReport(order, askQty[i], askPrice[i], type);
                    exeQtytotal = exeQtytotal + askQty[i];
                }
                qty = qty - askQty[i];
                i = i + 1;
                if (i > 5) {
                    break;
                }
            }
            if (qty > 0) {
                TradeSimOrderquene oq = this.getSimOrderquene(order);
                oq.setWorkingQty(qty);
                oq.setExeQty(exeQtytotal);
                this.putinSimOrderquene(oq);
            }
        }
    }

    private void dealSpecialOrder(NewOrder order, Price price) {
/*
        关于PriceType的说明：
        通用：0：普通市价单，1：限价单；
        上交：2:3：
        深交：4:5:6:7:8：
        */
        switch (order.getMarketCode()) {
            case "S": {
                if (order.getPriceType().equals("3")) {
                    this.MatchExe5Deal(order, 2, price);
                } else if (order.getPriceType().equals("2")) {
                    this.MatchExe5Deal(order, 1, price);
                }else{
                    ReportManager.CommitRejectReport(order);
                }
                break;
            }
            case "A": {
                switch (order.getPriceType()) {
                    case "4": {
                        this.MatchExeOneDeal(order, 1, price);
                        break;
                    }
                    case "5": {
                        this.MatchExeOneDeal(order, 2, price);
                        break;
                    }
                    case "6": {
                        this.MatchExe5Deal(order, 1, price);
                        break;
                    }
                    case "7": {
                        this.MatchExe5Deal(order, 1, price);
                        break;
                    }
                    case "8": {
                        this.MatchExe5Deal(order, 3, price);
                        break;
                    }

                }
                break;
            }
            case "H": {
                ReportManager.CommitRejectReport(order);
                break;
            }
            case "K": {
                ReportManager.CommitRejectReport(order);
                break;
            }
            case "L": {
                ReportManager.CommitRejectReport(order);
                break;
            }
            default: {
                ReportManager.CommitRejectReport(order);
            }

        }
    }
}
